/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.volley.toolbox;

import com.android.volley.AuthFailureError;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

/**
 * An Authenticator that uses {@link AccountManager} to get auth tokens of a
 * specified type for a specified account.
 */
public class AndroidAuthenticator implements Authenticator {
	private final Context mContext;
	private final Account mAccount;
	private final String mAuthTokenType;
	private final boolean mNotifyAuthFailure;

	/**
	 * Creates a new authenticator.
	 * 
	 * @param context
	 *            Context for accessing AccountManager
	 * @param account
	 *            Account to authenticate as
	 * @param authTokenType
	 *            Auth token type passed to AccountManager
	 */
	public AndroidAuthenticator(Context context, Account account,
			String authTokenType) {
		this(context, account, authTokenType, false);
	}

	/**
	 * Creates a new authenticator.
	 * 
	 * @param context
	 *            Context for accessing AccountManager
	 * @param account
	 *            Account to authenticate as
	 * @param authTokenType
	 *            Auth token type passed to AccountManager
	 * @param notifyAuthFailure
	 *            Whether to raise a notification upon auth failure
	 */
	public AndroidAuthenticator(Context context, Account account,
			String authTokenType, boolean notifyAuthFailure) {
		mContext = context;
		mAccount = account;
		mAuthTokenType = authTokenType;
		mNotifyAuthFailure = notifyAuthFailure;
	}

	/**
	 * Returns the Account being used by this authenticator.
	 */
	public Account getAccount() {
		return mAccount;
	}

	@Override
	public String getAuthToken() throws AuthFailureError {
		final AccountManager accountManager = AccountManager.get(mContext);
		AccountManagerFuture<Bundle> future = accountManager.getAuthToken(
				mAccount, mAuthTokenType, mNotifyAuthFailure, null, null);
		Bundle result;
		try {
			result = future.getResult();
		} catch (Exception e) {
			throw new AuthFailureError("Error while retrieving auth token", e);
		}
		String authToken = null;
		if (future.isDone() && !future.isCancelled()) {
			if (result.containsKey(AccountManager.KEY_INTENT)) {
				Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
				throw new AuthFailureError(intent);
			}
			authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
		}
		if (authToken == null) {
			throw new AuthFailureError("Got null auth token for type: "
					+ mAuthTokenType);
		}

		return authToken;
	}

	@Override
	public void invalidateAuthToken(String authToken) {
		AccountManager.get(mContext).invalidateAuthToken(mAccount.type,
				authToken);
	}
}
